using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;

namespace Sunny.UI;

public static class ArrayEx
{
    private const string DefaultCryptString = "!@#$%^&*";

    public static byte[] DesEncrypt(this byte[] data, string key = "Sunny.UI")
    {
        if (data == null)
        {
            return data;
        }
        try
        {
            byte[] bytes = Encoding.UTF8.GetBytes(key + "!@#$%^&*");
            byte[] bytes2 = Encoding.Unicode.GetBytes(key + "!@#$%^&*");
            using DES dES = DES.Create();
            using MemoryStream memoryStream = new MemoryStream();
            using CryptoStream cryptoStream = new CryptoStream(memoryStream, dES.CreateEncryptor(bytes.BlockCopy(0, 8), bytes2.BlockCopy(0, 8)), CryptoStreamMode.Write);
            cryptoStream.Write("!@#$%^&*".ToEnBytes("!@#$%^&*".Length), 0, "!@#$%^&*".Length);
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();
            memoryStream.Flush();
            return memoryStream.ToArray();
        }
        catch (Exception ex)
        {
            throw new Exception("DesEncrypt error, " + ex.Message);
        }
    }

    public static byte[] DesDecrypt(this byte[] data, string key = "Sunny.UI")
    {
        if (data == null)
        {
            return data;
        }
        try
        {
            byte[] bytes = Encoding.UTF8.GetBytes(key + "!@#$%^&*");
            byte[] bytes2 = Encoding.Unicode.GetBytes(key + "!@#$%^&*");
            using DES dES = DES.Create();
            using MemoryStream memoryStream = new MemoryStream();
            using CryptoStream cryptoStream = new CryptoStream(memoryStream, dES.CreateDecryptor(bytes.BlockCopy(0, 8), bytes2.BlockCopy(0, 8)), CryptoStreamMode.Write);
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();
            memoryStream.Flush();
            memoryStream.Position = "!@#$%^&*".Length;
            return memoryStream.ReadBytes(memoryStream.Length - memoryStream.Position);
        }
        catch (Exception ex)
        {
            throw new Exception("DesDecrypt error, " + ex.Message);
        }
    }

    internal static T[] BlockCopy<T>(this T[] array, int index, int length, bool padToLength = false)
    {
        if (array == null)
        {
            throw new NullReferenceException();
        }
        int num = length;
        T[] array2 = null;
        if (array.Length < index + length)
        {
            num = array.Length - index;
            if (padToLength)
            {
                array2 = new T[length];
            }
        }
        if (array2 == null)
        {
            array2 = new T[num];
        }
        Array.Copy(array, index, array2, 0, num);
        return array2;
    }

    public static byte[] ZLibCompress(this byte[] data)
    {
        MemoryStream memoryStream = new MemoryStream(data);
        MemoryStream memoryStream2 = new MemoryStream();
        DeflateStream deflateStream = new DeflateStream(memoryStream2, CompressionMode.Compress);
        memoryStream.CopyTo(deflateStream);
        deflateStream.Close();
        byte[] array = memoryStream2.ToArray();
        deflateStream.Dispose();
        memoryStream2.Close();
        memoryStream.Close();
        memoryStream2.Dispose();
        memoryStream.Dispose();
        byte[] array2 = new byte[array.Length + 6];
        array2[0] = 120;
        array2[1] = 218;
        Array.Copy(array, 0, array2, 2, array.Length);
        Array.Copy(Adler32.BigEndian(Adler32.ComputeHash(data, 0, data.Length)), 0, array2, array2.Length - 4, 4);
        return array2;
    }

    public static byte[] ZLibDecompress(this byte[] data)
    {
        int num = data[0] + data[1];
        List<byte> list = data.ToList();
        if (num == 121 || num == 276 || num == 338)
        {
            list.RemoveRange(0, 2);
            list.RemoveRange(list.Count() - 4, 4);
        }
        MemoryStream memoryStream = new MemoryStream(list.ToArray());
        MemoryStream memoryStream2 = new MemoryStream();
        DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress);
        deflateStream.CopyTo(memoryStream2);
        deflateStream.Close();
        byte[] result = memoryStream2.ToArray();
        deflateStream.Dispose();
        memoryStream.Close();
        memoryStream2.Close();
        memoryStream.Dispose();
        memoryStream2.Dispose();
        return result;
    }

    public static IntPtr Handle(this byte[] buffer)
    {
        return Marshal.UnsafeAddrOfPinnedArrayElement((Array)buffer, 0);
    }

    public static void Disorder<T>(this T[] data)
    {
        if (data != null && data.Length != 0)
        {
            int num = 1;
            int num2 = data.Length;
            int num3 = 0;
            Random random = new Random(DateTime.Now.Second * 1000 + DateTime.Now.Millisecond);
            while (num != num2)
            {
                int num4 = random.Next(num++, num2);
                T val = data[num3];
                data[num3] = data[num4];
                data[num4] = val;
                num3++;
            }
        }
    }

    public static byte[] ReadBytes(this Stream stream, long length = -1L)
    {
        if (stream == null)
        {
            return null;
        }
        if (length == 0L)
        {
            return new byte[0];
        }
        if (stream.CanSeek && stream.Length - stream.Position < length)
        {
            throw new Exception($"无法从长度只有{stream.Length - stream.Position}的数据流里面读取{length}字节的数据");
        }
        byte[] array = new byte[length];
        stream.Read(array, 0, array.Length);
        return array;
    }

    public static string ToBase64String(this byte[] b)
    {
        if (!b.IsNullOrEmpty())
        {
            return Convert.ToBase64String(b);
        }
        return "";
    }

    public static byte[] ToBase64Bytes(string b)
    {
        if (!b.IsNullOrEmpty())
        {
            return Convert.FromBase64String(b);
        }
        return new byte[0];
    }

    public static T MedianNum<T>(this T[] array) where T : IComparable
    {
        if (array.IsNullOrEmpty())
        {
            throw new NullReferenceException();
        }
        Array.Sort(array);
        return array[array.Length / 2];
    }

    public static bool IsNullOrEmpty(this IList source)
    {
        if (source != null)
        {
            return source.Count == 0;
        }
        return true;
    }

    public static bool IsValid(this IList source)
    {
        return !source.IsNullOrEmpty();
    }

    public static string ToHexString(this IEnumerable<byte> bytes, string span = "")
    {
        StringBuilder stringBuilder = new StringBuilder();
        foreach (byte @byte in bytes)
        {
            stringBuilder.Append(@byte.ToHexString());
            if (span.IsValid())
            {
                stringBuilder.Append(span);
            }
        }
        return stringBuilder.ToString();
    }

    public static string ToHexString(this byte b)
    {
        return b.ToString("X2");
    }

    public static byte[] ToHexBytes(this string str, string span = "")
    {
        if (!span.IsNullOrEmpty())
        {
            str = str.Replace(span, "");
        }
        if (str.IsNullOrEmpty())
        {
            return new byte[0];
        }
        if (str.Length.IsOdd())
        {
            throw new ArgumentException("str 长度应该为偶数");
        }
        byte[] array = new byte[str.Length / 2];
        try
        {
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = byte.Parse(str.Substring(2 * i, 2), NumberStyles.AllowHexSpecifier);
            }
            return array;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public static byte[] GZipCompress(this byte[] inputBytes)
    {
        if (inputBytes.IsNullOrEmpty())
        {
            return null;
        }
        using MemoryStream memoryStream = new MemoryStream();
        using GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true);
        gZipStream.Write(inputBytes, 0, inputBytes.Length);
        gZipStream.Close();
        return memoryStream.ToArray();
    }

    public static byte[] GZipDecompress(this byte[] inputBytes)
    {
        if (inputBytes.IsNullOrEmpty())
        {
            return null;
        }
        using MemoryStream stream = new MemoryStream(inputBytes);
        using MemoryStream memoryStream = new MemoryStream();
        using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress);
        gZipStream.CopyTo(memoryStream);
        gZipStream.Close();
        return memoryStream.ToArray();
    }

    public static byte[] DeflateCompress(this byte[] inputBytes)
    {
        if (inputBytes.IsNullOrEmpty())
        {
            return null;
        }
        using MemoryStream memoryStream = new MemoryStream();
        using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true);
        deflateStream.Write(inputBytes, 0, inputBytes.Length);
        deflateStream.Close();
        return memoryStream.ToArray();
    }

    public static byte[] DeflateDecompress(this byte[] inputBytes)
    {
        if (inputBytes.IsNullOrEmpty())
        {
            return null;
        }
        using MemoryStream stream = new MemoryStream(inputBytes);
        using MemoryStream memoryStream = new MemoryStream();
        using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress);
        deflateStream.CopyTo(memoryStream);
        deflateStream.Close();
        return memoryStream.ToArray();
    }

    public static void BubbleSort<T>(this T[] list) where T : IComparable
    {
        for (int i = 0; i < list.Length; i++)
        {
            for (int j = i; j < list.Length; j++)
            {
                T reference = list[i];
                T val = default(T);
                if (val == null)
                {
                    val = reference;
                    reference = val;
                }
                if (reference.CompareTo(list[j]) < 0)
                {
                    T val2 = list[i];
                    list[i] = list[j];
                    list[j] = val2;
                }
            }
        }
    }

    public static void InsertionSort(int[] list)
    {
        for (int i = 1; i < list.Length; i++)
        {
            int num = list[i];
            int num2 = i;
            while (num2 > 0 && list[num2 - 1] > num)
            {
                list[num2] = list[num2 - 1];
                num2--;
            }
            list[num2] = num;
        }
    }

    public static void SelectionSort(int[] list)
    {
        for (int i = 0; i < list.Length - 1; i++)
        {
            int num = i;
            for (int j = i + 1; j < list.Length; j++)
            {
                if (list[j] < list[num])
                {
                    num = j;
                }
            }
            int num2 = list[num];
            list[num] = list[i];
            list[i] = num2;
        }
    }

    public static void ShellSort(int[] list)
    {
        for (int num = 1; num <= list.Length / 9; num = 3 * num + 1)
        {
            while (num > 0)
            {
                for (int i = num + 1; i <= list.Length; i += num)
                {
                    int num2 = list[i - 1];
                    int num3 = i;
                    while (num3 > num && list[num3 - num - 1] > num2)
                    {
                        list[num3 - 1] = list[num3 - num - 1];
                        num3 -= num;
                    }
                    list[num3 - 1] = num2;
                }
                num /= 3;
            }
        }
    }

    public static void Swap<T>(ref T l, ref T r) where T : struct
    {
        T val = l;
        l = r;
        r = val;
    }

    public static void QuickSort(int[] list, int low, int high)
    {
        if (high <= low)
        {
            return;
        }
        if (high == low + 1)
        {
            if (list[low] > list[high])
            {
                Swap(ref list[low], ref list[high]);
            }
            return;
        }
        int num = low + high >> 1;
        int num2 = list[num];
        Swap(ref list[low], ref list[num]);
        int num3 = low + 1;
        int num4 = high;
        while (true)
        {
            if (num3 <= num4 && list[num3] < num2)
            {
                num3++;
                continue;
            }
            while (list[num4] >= num2)
            {
                num4--;
            }
            if (num3 < num4)
            {
                Swap(ref list[num3], ref list[num4]);
            }
            if (num3 >= num4)
            {
                break;
            }
        }
        list[low] = list[num4];
        list[num4] = num2;
        if (low + 1 < num4)
        {
            QuickSort(list, low, num4 - 1);
        }
        if (num4 + 1 < high)
        {
            QuickSort(list, num4 + 1, high);
        }
    }
}
